#include "GraphicsMoveOperation.h"
#include <GraphicsUtil.h>
#include <GraphicsBaseItem.h>


GraphicsMoveOperation::GraphicsMoveOperation(GraphicsBaseItemData& itemData, QObject* parent)
	:GraphicsBaseOperation(GraphicsOperationType::MoveOperation_Enum, itemData, parent)
{

}

QPointF GraphicsMoveOperation::onMoveEvent(const QPointF& newPos)
{
	if (!m_itemData.getParentItem())
		return newPos;

	QPointF returnPos = newPos;
	if (m_moveStrategy) {
		// 左右边界限制
		m_moveStrategy->horizontalLimit(newPos, returnPos);

		// 上下边界限制
		m_moveStrategy->verticalLimit(newPos, returnPos);
	}

	if (m_itemData.isMoving()) {
		adsorb(newPos, returnPos);
	}
	m_itemData.setCurPos(returnPos, false);
	return returnPos;
}

void GraphicsMoveOperation::setMoveStrategy(std::shared_ptr<MoveStrategy> moveStrategy)
{
	m_moveStrategy = moveStrategy;
}

qreal GraphicsMoveOperation::getDistanceToParentHorizontal(const QPointF& newPos)
{
	if (!m_itemData.getParentItem())
		return 0;

	const QRectF rect = m_itemData.getParentItem()->getItemData().getScaleRect();
	return newPos.y() - rect.height() / 2;
}

qreal GraphicsMoveOperation::getDistanceToParentVertical(const QPointF& newPos)
{
	if (!m_itemData.getParentItem())
		return 0;

	const QRectF rect = m_itemData.getParentItem()->getItemData().getScaleRect();
	return newPos.x() - rect.width() / 2;
}

qreal GraphicsMoveOperation::getDistanceToParentCenter(const QPointF& newPos)
{
	if (!m_itemData.getParentItem())
		return 0;
	const QRectF rect = m_itemData.getParentItem()->getItemData().getScaleRect();
	QLineF line(QPointF(rect.width() / 2, rect.height() / 2), newPos);
	return line.length();
}

void GraphicsMoveOperation::adsorb(const QPointF& newPos, QPointF& returnPos)
{
	const QRectF parentRect = m_itemData.getParentItem()->getItemData().getScaleRect();

	// 中心点吸附
	const qreal diffCenter = getDistanceToParentCenter(newPos);
	if (std::abs(diffCenter) < m_threshold * sqrt(2) + 6) {
		m_itemData.getParentItem()->setAbsorptionLineVisable(GraphicsLineType::HorizontalEnum, true);
		m_itemData.getParentItem()->setAbsorptionLineVisable(GraphicsLineType::VerticalEnum, true);
		returnPos.setX(parentRect.width() / 2);
		returnPos.setY(parentRect.height() / 2);
		return;
	}

	// 水平线吸附
	const qreal diffY = getDistanceToParentHorizontal(newPos);
	if (std::abs(diffY) < m_threshold) {
		m_itemData.getParentItem()->setAbsorptionLineVisable(GraphicsLineType::HorizontalEnum, true);
	}
	else {
		m_itemData.getParentItem()->setAbsorptionLineVisable(GraphicsLineType::HorizontalEnum, false);
	}
	if (std::abs(diffY) < m_threshold) {
		returnPos.setY(parentRect.height() / 2);
	}

	// 垂直线吸附
	const qreal diffX = getDistanceToParentVertical(newPos);
	if (std::abs(diffX) < m_threshold) {
		m_itemData.getParentItem()->setAbsorptionLineVisable(GraphicsLineType::VerticalEnum, true);
	}
	else {
		m_itemData.getParentItem()->setAbsorptionLineVisable(GraphicsLineType::VerticalEnum, false);
	}

	if (std::abs(diffX) < m_threshold) {
		returnPos.setX(parentRect.width() / 2);
	}
}
